// 简单版本
; (function () {
    return
    // 手写promise的两种实现方法
    // 1、class实现
    // 2、函数实现
    // 手写promise，首先要确认好promise的状态，主要有三种：pending、filfulled、rejected，其次是定义好filfulled的返回值value跟rejected的返回值reason，然后是resolve跟reject方法实现status改变及返回值更新，最后是then的实现，为promise的回调。

    // 注意：对于异步事件使用事件订阅发布实现监听

    // 1、class实现

    //实现promise
    class _promise {

        constructor(excutor) {
            var self = this;
            this.status = 'pending';
            this.value = null;
            this.reason = null;

            //事件缓存列表
            this.onFilfulledFns = []
            this.onRejectedFns = []

            //resolve
            function resolve(value) {
                if (self.status === 'pending') {
                    self.value = value;
                    self.status = 'filfulled';
                    //事件发布
                    self.onFilfulledFns.forEach(fn => fn(value))
                }
            }
            //reject
            function reject(reason) {
                if (self.status === 'pending') {
                    self.value = reason;
                    self.status = 'rejected';
                    //事件发布
                    self.onRejectedFns.forEach(fn => fn(reason))
                }
            }

            //执行器
            try {
                excutor(resolve, reject)
            } catch (err) {
                this.reject(err)
            }
        }
        //then
        then(onFilfulled, onRejected) {
            if (this.status === 'pending') {
                //事件订阅
                this.onFilfulledFns.push(onFilfulled);
                this.onRejectedFns.push(onRejected)
            } else if (this.status === 'filfulled') {
                onFilfulled(this.value)
            } else {
                onRejected(this.reason)
            }
        }
    }
    // 2、函数实现


    /**
     *
     * @param {*} excutor 执行器
     */
    function MyPromise(excutor) {

        let self = this;
        this.status = 'pending';
        this.value = null;
        this.reason = null;

        //事件缓存
        this.fulfilledFns = [];
        this.rejectedFns = [];
        // 成功响应
        function resolve(value) {
            if (self.status === 'pending') {
                self.value = value;
                self.status = 'fulfilled';
                //事件发布
                self.fulfilledFns.forEach(fn => fn(value))
            }
        }
        // 失败事件
        function reject(reason) {
            if (self.status === 'pending') {
                self.reason = reason;
                self.status = 'rejected';
                //事件发布
                self.rejectedFns.forEach(fn => fn(reason))
            }
        }

        //执行器
        try {
            excutor(resolve, reject)
        } catch (err) {
            reject(err)
        }
    }

    //then
    MyPromise.prototype.then = function (onFulfilled, onRejected) {
        let self = this;
        //异步事件订阅
        if (self.status === 'pending') {
            self.fulfilledFns.push(onFulfilled)
            self.rejectedFns.push(onRejected)
        } else if (self.status === 'fulfilled') {
            onFulfilled(self.value)
        } else {
            onRejected(self.reason)
        }

    }

    let demo = new MyPromise((resolve, reject) => {
        console.log('小伙很认真')
        setTimeout(() => {
            // 异步执行
            resolve(1)
        }, 1000);
    })

    demo.then(data => {
        console.log(data)
    })
})();

// 简单的promise执行顺序理解
; (function () {
    return
    let promiseSetTimeOut = function (val) {

        return new Promise((resolve, reject) => {
            console.log("promise的同步代码"); //同步2
            setTimeout(() => {
                console.log("我是一秒后的文字也有参数=>", val); //异步1
                resolve("你好,我是返回值")
            }, 1000)
        })
    }
    console.log("我是最开始的全局") // 同步1
    let myTime = promiseSetTimeOut('我就是一开始的参数') // ==>异步1
    console.log("我是中间") // 同步3
    myTime.then((data) => {
        console.log("我在then里面", data) //异步2
    })
    console.log("我是末尾,但是我是同步代码") // 同步4


    // 我是最开始的全局
    // promise的同步代码
    // 我是中间
    // 我是末尾,但是我是同步代码
    // 我是一秒后的文字也有参数=> 我就是一开始的参数
    // 我在then里面 你好,我是返回值
})();

// 为什么在then中有这样的判断
// if (this.status === PENDING) {
//     因为当new的时候, 构造函数内部代码可能是异步的,
//     那就会先执行then, 所以需要先缓存起来
//     this.onResolvedCallbacks.push(onFulfilled);
//     this.onRejectedCallbacks.push(onRejected);
// }
; (function () {
    return
    const PENDING = "PEDNING";
    const FULFILLED = "FULFILLED";
    const REJECTED = "REJECTED";
    class Promise2 {
        constructor(excutor) {
            this.status = PENDING;
            this.value = undefined;
            this.reason = undefined;
            this.onResolvedCallbacks = [];
            this.onRejectedCallbacks = [];
            const resolve = (value) => {
                console.log("再先执行的我")
                if (this.status === PENDING) {
                    this.value = value;
                    this.status = FULFILLED;
                    this.onResolvedCallbacks.forEach((cb) => cb(this.value));
                }
            };
            const reject = (reason) => {
                if (this.status === PENDING) {
                    this.reason = reason;
                    this.status = REJECTED;
                    this.onRejectedCallbacks.forEach((cb) => cb(this.reason));
                }
            };

            try {
                excutor(resolve, reject);
            } catch (err) {
                reject(err);
            }
        }
        then(onFulfilled, onRejected) {
            if (this.status === FULFILLED) {
                onFulfilled(this.value);
            }
            if (this.status === REJECTED) {
                onRejected(this.reason);
            }
            if (this.status === PENDING) {
                console.log("先执行的我")
                this.onResolvedCallbacks.push(onFulfilled);
                this.onRejectedCallbacks.push(onRejected);
            }
        }
    }

    let obj = new Promise2((resolve, reject) => {
        setTimeout(() => {
            resolve(1)
        })

    }).then((data) => {
        console.log(data);
    }, () => { })


    // 先执行的我
    // {}
    // 再先执行的我
    // 1
})();

// 为什么有数组缓存,不用一个变量就行了
// 为了可以一个promise绑定多个then函数 (这种写法很少)
; (function () {
    // return
    const mypromise = new Promise((resolve, reject) => {
        resolve('成功')
    })

    mypromise.then(data => {
        console.log(data, '1')
    })

    mypromise.then(data => {
        console.log(data, '2')
    })

    //  成功 1
    //  成功 2
})();


// 难点
// 链式调用
; (function () {
    // return
    const STATUS = {
        PENDING: 'pending',
        FULFILLED: 'fulfilled',
        REJECTED: 'rejected'
    }
    let num = 1
    class MyPromise {

        constructor(executor) {
            // 执行器
            try {
                if (num == 2) {
                    this.name = 'then'
                } else {
                    this.name = num
                }
                num++
                executor(this.resolve, this.reject)
            } catch (error) {
                this.reject(error)
            }
        }

        // 初始状态为 pending
        status = STATUS.PENDING

        // 成功返回值
        value = null

        // 失败返回值
        reason = null

        // 成功回调
        onFulfilledCallbacks = []

        // 失败回调
        onRejectedCallbacks = []


        // 修改 Promise 状态，并定义成功返回值
        resolve = value => {
            console.log(this.name, value)
            if (this.status === STATUS.PENDING) {
                this.status = STATUS.FULFILLED
                this.value = value
                // this.onFulfilledCallbacks.forEach(fn => fn())
                while (this.onFulfilledCallbacks.length) {
                    this.onFulfilledCallbacks.shift()(value)
                }
            }
        }

        // 修改 Promise 状态，并定义失败返回值
        reject = reason => {
            if (this.status === STATUS.PENDING) {
                this.status = STATUS.REJECTED
                this.reason = reason
                // this.onRejectedCallbacks.forEach(fn => fn())
                while (this.onRejectedCallbacks.length) {
                    this.onRejectedCallbacks.shift()(reason)
                }
            }
        }

        then = function (onFulfilled, onRejected) {
            // onFulfilled、onRejected 是可选参数 不是函数则必须忽略它
            const realOnFulfilled = onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
            const realOnRejected = onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error }

            const promise2 = new MyPromise((resolve, reject) => {
                // 报错：Cannot access 'promise2' before initialization | 不能访问 promise2 在初始化之前
                // 原因：在 new promise 时，promise2 还没有完成初始化,所以 resolvePromise 中不能访问到 promise2
                // 在当前的执行上下文栈中，onFulfilled 或 onRejected 是不能被直接调用的
                // onFulfilled 或 onRejected 得是在当前事件循环后异步执行的
                // 可以使用 setTimeout、setImmediate、MutationObserever、process.nextTick在 then 方法被调用后将创建一个新的栈

                const fulfilledMicrotask = () => {
                    // 创建一个微任务等待 promise2 完成初始化
                    queueMicrotask(() => {
                        try {
                            // 获取成功回调函数的执行结果
                            // console.log(this.value,'value')
                            const x = realOnFulfilled(this.value)
                            // console.log(x instanceof MyPromise)
                            // 传入 resolvePromise 集中处理
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            console.log("错误进来了", error)
                            reject(error)
                        }
                    })
                }

                const rejectedMicrotask = () => {
                    console.log('jinlai2222222222222')
                    queueMicrotask(() => {
                        try {
                            // 获取成功回调函数的执行结果
                            const x = realOnRejected(this.reason)
                            // 传入 resolvePromise 集中处理
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                }

                if (this.status === STATUS.PENDING) {
                    this.onFulfilledCallbacks.push(fulfilledMicrotask)
                    this.onRejectedCallbacks.push(rejectedMicrotask)
                } else if (this.status === STATUS.FULFILLED) {
                    console.log("因为先,所以进来");
                    fulfilledMicrotask()
                } else if (this.status === STATUS.REJECTED) {
                    rejectedMicrotask()
                }
            })

            return promise2
        }
    }
    // 如果 promise2 === x， 执行 reject，错误原因为 TypeError
    // 如果 x 是函数或对象
    //      如果 x.then 是函数
    //          执行 x.then
    //      如果 x.then 不是函数
    //          执行 resolve(x)
    // 如果 x 不是函数或对象
    //      执行 resolve(x)
    function resolvePromise(promise2, x, resolve, reject) {
        // 如果 promise2 === x 执行 reject，错误原因为 TypeError
        if (promise2 === x) {
            reject(new TypeError('The promise and the return value are the same'))
        }

        // 如果 x 是函数或对象
        if ((typeof x === 'object' && x != null) || typeof x === 'function') {
            let then
            try {
                then = x.then
            } catch (error) {
                reject(error)
            }

            // 如果 x.then 是函数
            if (typeof then === 'function') {
                // Promise/A+ 2.3.3.3.3 只能调用一次
                let called = false
                try {
                    then.call(x, y => {
                        console.log("进来一次")
                        // resolve的结果依旧是promise 那就继续解析 | 递归解析
                        if (called) return
                        called = true
                        resolvePromise(promise2, y, resolve, reject)
                    }, err => {
                        if (called) return
                        called = true
                        reject(err)
                    })
                } catch (error) {
                    if (called) return
                    reject(error)
                }
            } else {
                console.log(x, 'x.then不是函数')
                // 如果 x.then 不是函数
                resolve(x)
            }
        } else {
            console.log(x, 'x是普通值')
            // 如果 x 是个普通值就直接返回 resolve 作为结果  Promise/A+ 2.3.4  
            resolve(x)
        }
    }



    // 创建一个Promise对象  
    const promise = new MyPromise((resolve, reject) => {
        // 模拟异步操作  
        setTimeout(() => {
            resolve('成功的结果');
        }, 1000);
        // resolve('成功的结果');
        // console.log('执行了')
    });


    // 第一个then回调函数 
    let err = error => {
    }
    let reject = reject => { }
    let resultOne = result => {
        console.log('第一个then:', result);
        return new MyPromise((resolve, reject) => {
            // console.log("这是同步")
            setTimeout(() => { resolve(666); }, 100)
            //    return 5
        })
    }
    let resultTwo = result => {
        console.log('第二个then:', result);
        // return new MyPromise((resolve) => {
        //     setTimeout(()=>{resolve(666)},1000)
        // }, reject)
    }

    // const promiseN = new MyPromise((resolve,reject) => {
    //     console.log("这是同步")
    //     setTimeout(()=>{resolve(666);},100)
    // })

    // return
    promise
        //关键点就是这一步
        .then(resultOne, err)
    // ================================= 过程解释
    then(onFulfilled, onRejected){
        // 这里就是return出去的promise
        // 这是可以链式调用的基础 记为主体promise
        return new MyPromise((resolve, reject) => {

            // onFulfilled()  先执行一遍.
            let x = onFulfilled()
            // x作为结果传进去
            resolvePromise(promise2, x, resolve, reject)
            // 函数内部=======>
            // 接受主体的resolve, reject (主体函数)
            // 先判断x是不是promise
            //  x是promise
            // ============
            // x再次调用then(方法1,方法2)
            // 当x为fulfilled,会执行方法1==>
            // y => {resolvePromise(promise2, y, resolve, reject)}
            // 接受主体的resolve, reject (主体函数)
            // y是 x的value值, 因为x的resolve方法会赋值x.value
            // 这个时候执行resolvePromise(promise2, y, resolve, reject)
            // =============
            // resolvePromise 内部执行,
            // 接受主体的resolve, reject (主体函数)
            // 这个时候 y不是promise了, 且是y是x中resolve传递的值.
            // 所以直接执行 主体函数的resolve(y) 这里就完成闭环
            // 先判断x不是promise
            //  主体函数的resolve(x),直接闭环
        }) //
    }
    // =================================


})();

// Promise.all的方法应用
; (function () {
    return
    // static all(promises) {
    //     let result = [];
    //     let times = 0;
    //     return new Promise((resolve, reject) => {
    //
    //         function processResult(data, index) {
    //           //方法是把结果存起来, 
    //             result[index] = data;
    //           //全部完成时,一起resolve出去, 
    //             if (++times === promises.length) {
    //                 resolve(result);
    //             }
    //         }
    //         for (let i = 0; i < promises.length; i++) {
    //             const promise = promises[i];
    //             Promise.resolve(promise).then((data) => {
    //               //每次有结果都调用这个方法
    //                 processResult(data, i);
    //             }, reject);
    //         }

    //     });
    // }
    let one = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("one11")
        }, 1000)

    })
    let two = new Promise((resolve, reject) => {
        resolve("two22")
    })

    let three = Promise.all([one, two]).then(res => {
        console.log(res)
    }, null)
})();

// Promise.race
; (function () {
    //return
    //   static race(promises) {
    //     return new Promise((resolve, reject) => {
    //         for (let i = 0; i < promises.length; i++) {
    //             let promise = promises[i];
    //             // 谁先resolve谁就调用了主体的resolve, 然后外面then就能接受到.
    //             Promise.resolve(promise).then(resolve, reject);
    //         }
    //     });
    // }
})();

// Promise.finally
;(function(){
  //return
  //  finally(finallyCallback) {
//     let p = this.constructor;
//     return this.then(
//          (data) => {
//              return p.resolve(finallyCallback()).then(() => data);
//          },
//          (err) => {
//              return p.resolve(finallyCallback()).then(() => {
//                  throw err;
//           });
// }
//     );
// }
// 近似看成下面的写法
// let one = new Promise((resolve, reject) => {
//     resolve(1)
// }).then(data => {
//     return Promise.resolve(6).then(() => data);
// },
//     err => {
//         return Promise.resolve(6).then(() => {
//             throw err;
//         })
//     }).then((res) => {
//         console.log(res,8989)
//     },err=>{
//         console.log(err);
//     })
// 如果在finally中报错会怎么样
let one = new Promise((resolve, reject) => {
    reject('错误')
}).then(data => {
    console.log("进来res")
    return Promise.resolve(6).then(() => data);
},
    err => {
        console.log("进来err")
        return Promise.resolve(6).then(() => {
            // 这里会触发 try catch, 然后再调用reject传递下去
            throw err;
        })
    }).then((res) => {
        console.log(res,8989)
    },err=>{
        console.log(err,'error'); //传递到这就接收到了
    })




})();